/*
 * sma.c
 *
 *  Created on: Apr 2, 2012
 *      Author: Tri_D
 */

#include "sma.h"
#include "serial.h"
#include "queue.h"
#include "string.h"
#include "system.h"
#include "font.h"

/*
 *  Initialize SMA package
 */
void SMA_Init(SMA_Pkg_t * pS)
{
	pS->Start = 0;
	pS->End = 0;
	pS->Future = 0;
	pS->Mode = 0;
	pS->Motion = 0;
	pS->Range = 0;
	pS->Status = 0;
	(void) memset(pS->Msg, 0, SMA_MAX_MSG_CHAR);
	pS->M_Ptr = 0;
	pS->U_Ptr = 0;
	(void) memset(pS->Unit, 0, SMA_FIXED_UNIT_MSG);
	pS->State = OBTAIN_START;
}



/*
 * Collect data in SMA format
 * Handle time out logic outside of this function to ensure no locked up
 * Return TRUE if a SMA package is received
 *        FALSE otherwise
 */
BOOL Collect_SMA_Pkg(que_512 * pQ, SMA_Pkg_t * pS)
{
	BOOL res_ = FALSE;
	uint8_t ch = 0;
	
	switch(pS->State)
	{
		case OBTAIN_START:
		{
			if(get_chr512(pQ, &ch) == TRUE)
			{
				if (ch == SMA_START_SIG)
				{
					pS->Start = ch;					
					pS->State = OBTAIN_STATUS;
				}
			}
		}
		break;
		
		case OBTAIN_STATUS:
		{
			if(get_chr512(pQ, &ch) == TRUE)
			{
				pS->Status = ch;
				if (ch == 'X')			// If this is extended message then obtain msg right away
					pS->State = OBTAIN_MSG;
				else
					pS->State = OBTAIN_RANGE;
			}
		}
		break;
		
		case OBTAIN_RANGE:
		{
			if(get_chr512(pQ, &ch) == TRUE)
			{
				pS->Range = ch;
				pS->State = OBTAIN_MODE;
			}
		}
		break;
		
		case OBTAIN_MODE:
		{
			if(get_chr512(pQ, &ch) == TRUE)
			{
				pS->Mode = ch;
				pS->State = OBTAIN_MOTION;
			}
		}
		break;
		
		case OBTAIN_MOTION:
		{
			if(get_chr512(pQ, &ch) == TRUE)
			{
				pS->Motion = ch;
				pS->State = OBTAIN_FUTURE;
			}
		}
		break;
		
		case OBTAIN_FUTURE:
		{
			if(get_chr512(pQ, &ch) == TRUE)
			{
				pS->Future = ch;
				pS->State = OBTAIN_MSG;
			}
		}
		break;
		
		case OBTAIN_MSG:
		{
			if(pS->Status == 'X')						// Extended SMA message
			{
				if(get_chr512(pQ, &ch) == TRUE)
				{
					if(ch != SMA_END_SIG)			// Only accept the first 12 msg bytes
					{
						pS->Msg[pS->M_Ptr] = ch;
						ch = 0;
						if(pS->M_Ptr < SMA_MAX_MSG_CHAR)
							pS->M_Ptr++;
					}
					else
					{
						pS->End = SMA_END_SIG;
						pS->State = OBTAIN_END;
					}
				}				
			}
			else											// SMA weight message
			{
				if(get_chr512(pQ, &ch) == TRUE)
				{
					if(ch != SMA_END_SIG)
					{
						pS->Msg[pS->M_Ptr] = ch;
						ch = 0;
						if (pS->M_Ptr < SMA_FIXED_WT_MSG)	// Only accept the first 10 digit weights
							pS->M_Ptr++;
					}
					else
					{
						pS->End = SMA_END_SIG;
						pS->State = OBTAIN_END;
					}
				}									
				if(pS->M_Ptr >= SMA_FIXED_WT_MSG)
					pS->State = OBTAIN_UNIT;
			}
		}
		break;
		
		case OBTAIN_UNIT:
		{
			if(get_chr512(pQ, &ch) == TRUE)
			{
				if(ch != SMA_END_SIG)
				{
					pS->Unit[pS->U_Ptr] = ch;
					ch = 0;
					if (pS->U_Ptr < SMA_FIXED_UNIT_MSG)	// Only accept the first 3 digit unit
						pS->U_Ptr++;
				}
				else
				{
					pS->End = SMA_END_SIG;
					pS->State = OBTAIN_END;
				}
			}			
		}
		break;
		
		case OBTAIN_END:
		{
			res_ = TRUE;
		}
		break;	
	}

	return res_;
}


/*
 *  Ascii string with variable lengths
 *  size indicates number of values separated by comma
 *  Format: "value, value, value"
 *  value "0" - "255" 
 */
void Extract_Ascii_Info(uint8_t * pd, uint8_t *pdes, uint8_t num)
{
	uint8_t str[3];
	uint8_t c, c2;
	uint8_t count_, count2_ = 0;
	
	// Obtain the string value
	for(c = 0; c <num; c++)
	{
		c2 = 0;
		count_ =0;
		(void) memset(str, 0, 3);
		c2 = *(pd+count2_++);
		while(c2 != 0 && c2  != ',' && count_ <= 3)
		{
			str[count_++] = c2;
			c2 = *(pd+count2_++);
		}
		*(pdes+c) = Ascii2Val(str, count_);
	}
}


/*
 * Return the number of '.' or ',' are found in the string 
 * 		  0 if none
 */
uint8_t Search_Dcp(uint8_t *pd, uint8_t size)
{
	uint8_t c;
	uint8_t count_ = 0;
	for(c=0;c<size;c++)
	{
		if(*(pd+c) == '.' || *(pd+c) == ',')
		{
			count_++;
		}
	}
	return count_;
}

/*
 * Process SMA package. Detailed of recognized format is listed in sma.h
 * pd will store the final string to be displayed on the screen
 * pAnnuc is system annunciation that will be updated
 * pMode is system mode that will be updated
 * pUnit is system unit that will be updated 
 * pColor is backlight color to be updated
 * Assume: a SMA pkg is fully received
 */
void Process_SMA(SMA_Pkg_t *pS, uint8_t * pd, uint16_t * pAnnuc, uint8_t * pMode, uint8_t * pUnit, uint8_t * pcolor, Bat_t * pBat, BOOL * pUpdate)
{
	uint8_t count_ = 0;
	uint8_t c = 0;
	if(pS->Start == SMA_START_SIG && pS->End == SMA_END_SIG)
	{
		*pUpdate = 0;
		switch(pS->Status)
		{
			case 'X':				// Extended SMA msg
			{
				if(strncmp("BKLGHT:", pS->Msg, 7) == 0)				// Blacklight colors
				{
					// Red, Green, Blue
					Extract_Ascii_Info(&pS->Msg[7], pcolor, 3);
				}
				else if (strncmp("TIME:", pS->Msg, 5) == 0)			// time 
				{
					(void) memcpy(pd, &pS->Msg[5], 8);
					*pUpdate = 1;
				}
				else if (strncmp("TEXT:", pS->Msg, 5) == 0)			// Text
				{
					(void) memset(pd, 0, 9);
					c = pS->Msg[5];
					while(c != 0 && count_ < 6)
					{
						*(pd+count_) = c;
						count_++;
						c = pS->Msg[5+count_];						
					}
					*pUpdate = 1;
				}
				else if (strncmp("ANN:", pS->Msg, 4) == 0)			// Annunciation for down arrows
				{
					c = pS->Msg[4];
					for(count_ =0; count_ < 8; count_++)
					{
						if (c & (1<<count_))
							*(pAnnuc) |= (DOWN_ARROW8<<count_);
						else
							*(pAnnuc) &= ~(DOWN_ARROW8<<count_);						
					}
					*pUpdate = 1;
				}
				else if (strncmp("CAL:", pS->Msg, 4) == 0)			// Calibration required
				{
					if(pS->Msg[4] == '1')
						*(pAnnuc) |= CAL_LED;
					else
						*(pAnnuc) &= ~CAL_LED;
					*pUpdate = 1;
				}
				else if (strncmp("BATT:", pS->Msg, 5) == 0)			// battery
				{
					*(pBat) = (Bat_t) (pS->Msg[5]-'0'); 
					*pUpdate = 1;
				}
			}
				break;
				
			case 'Z':				// Center of zero
			case 'O':				// Over capacity
			case 'U':				// Under capacity
			case 'E':				// Zero Error
			case 'I':				// Initial zero error
			case 'T':				// Tare error
			case ' ':				// none of the above
			{
				(void) memset(pd , 0, 9);
				/*** Process status first ***/
				if(pS->Status == 'Z')
					*(pAnnuc) |= ZERO_LED;
				else
					*(pAnnuc) &= ~ZERO_LED;				
				
				if(pS->Status == 'E' || pS->Status == 'I' || pS->Status == 'T')
				{
					(void) memcpy(pd, "------", 6);
				}
				else if (pS->Status == 'O')
				{
					(void) memcpy(pd, " ocap ", 6); 							
				}
				/*** Ignore range ***/
				/*** Process mode ***/
				if(pS->Mode == 'G' || pS->Mode == 'N' || pS->Mode == 'T' || pS->Mode == 'g' || pS->Mode == 'n')
					*pMode = pS->Mode;
				else
					*pMode = ' ';
				/*** Process motion ***/
				if(pS->Motion == ' ')
					*(pAnnuc) |= STABLE_LED;
				else
					*(pAnnuc) &= ~STABLE_LED;				
				/*** Ignore future ***/
				/*** Process weight ***/
				if (pS->Status != 'E' && pS->Status != 'I' && pS->Status != 'T' && pS->Status != 'O')
				{
					c = Search_Dcp(pS->Msg, SMA_FIXED_WT_MSG);			// find decimal points
					(void) memcpy(pd, &pS->Msg[4-c], 6+c);
				}
				/*** Process unit ***/
				(void) memcpy(pUnit, pS->Unit, 3);
				*pUpdate = 1;
			}
				break;
				
			default:
			{
				
			}
				break;
		}
	}
}